#include "RecordBase.h"
#include <boost/algorithm/string/replace.hpp>
#include <sstream>

namespace serika
{
	namespace db
	{
		Adapter* RecordBase::mDefaultAdapter = 0;
		std::vector<Adapter*> RecordBase::mAdapters;
		Adapter* RecordBase::mNullAdapter = 0;
	
		RecordBase::RecordBase()
			: mReadOnly(false), mModified(false)
		{
			mFields = new FieldMap;
		}
	
		RecordBase::RecordBase(FieldMap* fields, bool readOnly)
		{
			mFields = fields; 
			mReadOnly = readOnly; 
			mModified = false;
		}
	
		RecordBase::RecordBase(const RecordBase& other)
		{
			mFields = new FieldMap;
			for (FieldMap::const_iterator itr = other.mFields->begin(); itr != other.mFields->end(); ++itr)
			{
				ut::String v = itr->second.ToString();
				boost::replace_all(v, _T("\""), _T("\\\""));
				mFields->insert(std::make_pair(itr->first, v));
			}
			mReadOnly = other.mReadOnly;
			mErrors = other.mErrors;
		}
	
		RecordBase::~RecordBase()
		{
			if (mFields)
			{
				delete mFields;
				mFields = 0;
			}
		}
	
		void RecordBase::Assign(FieldMap* fields)
		{
			if (mFields != 0)
			{
				delete mFields;
			}
			mFields = fields;
		}
	
		void RecordBase::DoValidate()
		{
			this->BeforeValidation();
			this->Validate();
			this->AfterValidation();
		}
	
		RecordBase& RecordBase::operator =(const RecordBase& other)
		{
			if (mFields)
			{
				delete mFields;
				mFields = 0;
			}
	
			mFields = new FieldMap;
			for (FieldMap::const_iterator itr = other.mFields->begin(); itr != other.mFields->end(); ++itr)
			{
				mFields->insert(std::make_pair(itr->first, itr->second));
			}
			mModified = other.mModified;
			mReadOnly = other.mReadOnly;
			return *this;
		}
	
		bool RecordBase::Initialize(const std::string& adapterName, const Any& initInfo)
		{
			Adapter* adapter = Adapter::Create(adapterName, initInfo);
			if (adapter != 0)
			{
				RecordBase::mAdapters.push_back(adapter);
				if (RecordBase::mAdapters.size() == 1)
				{
					RecordBase::mDefaultAdapter = adapter;
				}
				return true;
			}
			else
			{
				return false;
			}
		}
	
		void RecordBase::Finalize()
		{
			for (std::vector<Adapter*>::iterator itr = RecordBase::mAdapters.begin(); itr != RecordBase::mAdapters.end(); ++itr)
			{
				(*itr)->Destroy();
			}
			RecordBase::mAdapters.clear();
			RecordBase::mDefaultAdapter = 0;
		}
	
		void RecordBase::SetValue(const std::string& name, const db::Any& value)
		{
			if (mFields == 0)
			{
				return;
			}
			mFields->operator[](name) = value;
			mModified = true;
		}
	
		const Any& RecordBase::GetValue(const std::string& name) const
		{
			if (mFields == 0)
			{
				return NIL;
			}
	
			FieldMap::iterator itr = mFields->find(name);
			if (itr == mFields->end())
			{
				return NIL;
			}
			return itr->second;
		}
	
		bool RecordBase::IsValueNil(const std::string& name) const
		{
			if (mFields == 0)
			{
				return false;
			}
			FieldMap::iterator itr = mFields->find(name);
			if (itr == mFields->end())
			{
				return true;
			}
			return itr->second.IsNil();
		}
	
		FieldMap* RecordBase::CloneFields() const
		{
			FieldMap* f = new FieldMap;
			for (FieldMap::iterator itr = mFields->begin(); itr != mFields->end(); ++itr)
			{
				f->insert(std::make_pair(itr->first, itr->second));
			}
			return f;
		}
	
		bool RecordBase::Save(bool throwOnError)
		{
			if (!mModified)
			{
				return true;
			}
			if (mReadOnly)
			{
				if (throwOnError)
				{
					throw RecordException(-1, _T("Save on readonly record"));
				}
				return false;
			}
	
			mErrors.Clear();
			this->Validate();
	
			if (!mErrors.IsEmpty())
			{
				if (throwOnError)
				{
					throw RecordException(-1, _T("Record validation failed"));
				}
				return false;
			}
	
			this->BeforeSave();
			bool ret = false;
			bool created = false;
			try
			{
				FieldMap::iterator itr = mFields->find(this->GetPrimaryKeyI());
				if (itr == mFields->end())
				{
					created = true;
					this->BeforeCreate();
					ret = this->GetAdapterI()->CreateRecord(mFields, this->GetTableNameI(), this->GetPrimaryKeyI());
					if (ret)
					{
						this->AfterCreate();
					}
				}
				else
				{
					this->BeforeUpdate();
					ret = this->GetAdapterI()->UpdateRecord(mFields, this->GetTableNameI(), itr->first, itr->second);
					if (ret)
					{
						this->AfterUpdate();
					}
				}
			}
			catch (RecordException& e)
			{
				if (throwOnError)
				{
					throw e;
				}
				return false;
			}
			if (ret)
			{
				this->AfterSave();
			}
			else if (throwOnError)
			{
				throw RecordException(-1, _T("Failed on saving"));
			}
			return ret;
		}
	
		bool RecordBase::UpdateAttribute(const std::string& name, const Any& value)
		{
			mFields->operator[](name) = value;
	
			mErrors.Clear();
			this->DoValidate();
	
			if (!mErrors.IsEmpty())
			{
				return false;
			}
	
			FieldMap::iterator itr = mFields->find(this->GetPrimaryKeyI());
			if (itr == mFields->end())
			{
				mErrors.Add("No primary key exists");
				return false;
			}
	
			this->BeforeSave();
			this->BeforeUpdate();
		
			FieldMap fm;
			fm.insert(std::make_pair(name, value));
			bool ret = false;
			try
			{
				ret = this->GetAdapterI()->UpdateRecord(&fm, this->GetTableNameI(), itr->first, itr->second);
			}
			catch(RecordException&)
			{
				return false;
			}
	
			if (ret)
			{
				this->AfterUpdate();
				this->AfterSave();
			}
			return ret;
		}
	
		bool RecordBase::UpdateAttributes(const FieldMap* fields)
		{
			for (FieldMap::const_iterator itr = fields->begin(); itr != fields->end(); ++itr)
			{
				mFields->operator[](itr->first) = itr->second;
			}
	
			mErrors.Clear();
			this->DoValidate();
	
			if (!mErrors.IsEmpty())
			{
				return false;
			}
	
			FieldMap::iterator itr = mFields->find(this->GetPrimaryKeyI());
			if (itr == mFields->end())
			{
				mErrors.Add("No primary key exists");
				return false;
			}
	
			this->BeforeSave();
			this->BeforeUpdate();
	
			bool ret = false;
			try
			{
				ret = this->GetAdapterI()->UpdateRecord(fields, this->GetTableNameI(), itr->first, itr->second);
			}
			catch(RecordException&)
			{
				this->AfterSave();
				return false;
			}
	
			if (ret)
			{
				this->AfterUpdate();
				this->AfterSave();
			}
			return ret;
		}
	
		void RecordBase::Destroy()
		{
			this->BeforeDestroy();
			FieldMap::iterator itr = mFields->find(this->GetPrimaryKeyI());
			if (itr == mFields->end())
			{
				return;
			}
			try
			{
				std::string conditions = this->GetAdapterI()->ConstructConditions(itr->first, itr->second);
				this->GetAdapterI()->DeleteRecord(conditions, this->GetTableNameI());
				mReadOnly = true;
			}
			catch (RecordException&)
			{
				return;
			}
			this->AfterDestroy();
		}
	
		ut::String RecordBase::ToString() const
		{
			ut::Sstream ss;
			ss << (*this);
			return ss.str();
		}
	
		bool RecordBase::ParseString(const ut::String& text)
		{
			ut::Sstream ss(text);
			ss >> this;
			return true;
		}
	}
	
	using namespace db;
	
	ut::Ostream& operator << (ut::Ostream& s, const FieldMap& fields)
	{
		s << _T("{");
		for (FieldMap::const_iterator itr = fields.begin(); itr != fields.end(); ++itr)
		{
			if (itr != fields.begin())
			{
				s << _T(",");
			}
			s << itr->first << _T(":");
			itr->second.ToPersistence(s);
		}
		s << _T("}");
		return s;
	}
	
	ut::Istream& operator >> (ut::Istream& s, FieldMap& fields)
	{
		fields.clear();
	
		const size_t length = 1024;
		ut::Char buf[length] = {0};
		ut::Char ch = s.get();
	
		if (ch != '{' || s.eof())
		{
			return s;
		}
	
		do
		{
			s.get(buf, length, ':');
			if (s.eof())
			{
				break;
			}
			buf[s.gcount()] = 0;
			ut::String name(buf);
	
			s.get();	// skip the colon
	
			Any value;
			value.FromPersistence(s);
	
			fields.insert(std::make_pair(TO_ASTRING(name), value));
	
			ch = s.get();
			if (ch == '}')
			{
				break;
			}
			else if (ch != ',')
			{
				break;
			}
		} while(!s.eof());
		return s;
	}
	
	ut::Ostream& operator << (ut::Ostream& os, const FieldMap* fields)
	{
		return operator << (os, *fields);
	}
	
	ut::Istream& operator >> (ut::Istream& is, FieldMap* fields)
	{
		return operator >> (is, *fields);
	}
	
	ut::Ostream& operator << (ut::Ostream& s, const RecordBase& rb)
	{
		const FieldMap& fields = rb.GetFields();
		return (s << fields);
	}
	
	ut::Istream& operator >> (ut::Istream& s, RecordBase& rb)
	{
		FieldMap* fields = new FieldMap;
		s >> fields;
		rb.Assign(fields);
		return s;
	}
	
	ut::Ostream& operator << (ut::Ostream& os, const RecordBase* rb)
	{
		return operator << (os, *rb);
	}
	
	ut::Istream& operator >> (ut::Istream& is, RecordBase* rb)
	{
		return operator >> (is, *rb);
	}
}
